package com.zhou;

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.*;
import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
import net.sf.jsqlparser.expression.operators.relational.*;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.create.table.ColDataType;

import java.util.ArrayList;
import java.util.List;

/**
 * @author zhouzhihao
 * @version V1.0
 * @since 2022/6/3 22:32
 */
public class ReplaceUtil {

    /**
     * 替换 函数部分
     *
     * @param function 函数
     */
    public static void replaceFunction(Function function) {
        if (function == null)
            return;
        String name = function.getName();
        // 替换 to_date 函数
        if (Constants.TO_DATE.equalsIgnoreCase(name)) {
            replaceToDate(function);
        }
        // 替换 to_char 函数
        else if (Constants.TO_CHAR.equalsIgnoreCase(name)) {
            replaceToChar(function);
        }
        // 替换 trunc() 函数
        else if (Constants.TRUNC.equalsIgnoreCase(name)) {
            replaceTrunc(function);
        }
        // 替换 nvl
        else if (Constants.NVL.equalsIgnoreCase(name)) {
            replaceNVL(function);
        }
        // 替换 decode
        else if (Constants.DECODE.equalsIgnoreCase(name)) {
            replaceDecode(function);
        }
        // 替换 to_number
        else if (Constants.TO_NUMBER.equalsIgnoreCase(name)) {
            replaceToNumber(function);
        }
    }

    private static void replaceToNumber(Function function) {
        List<Expression> expressions = function.getParameters().getExpressions();
        Expression expression = expressions.get(0);
        if (expression instanceof Column){
            Column column = (Column) expression;
            column.setColumnName(column.getColumnName() + " AS SIGNED INTEGER");
        }
        function.setName(Constants.CAST);
    }

    /**
     * 将 oracle 的 to_date 函数 替换成 mysql 的 str_to_date 函数
     *
     * @param function to_date expression
     */
    private static void replaceToDate(Function function) {
        Expression expression = function.getParameters().getExpressions().get(1);
        if (expression instanceof StringValue) {
            StringValue stringValue = (StringValue) expression;
            // 执行日期替换
            ExecutionDateReplacement(stringValue);
        }
        // 将 to_date 转换成 str_to_date
        function.setName(Constants.STR_TO_DATE);
    }


    /**
     * 处理 oracle 的 to_char 函数
     *
     * @param function to_char expression
     */
    private static void replaceToChar(Function function) {
        List<Expression> expressions = function.getParameters().getExpressions();
        int size = expressions.size();
        // to_char 函数 将数值转换成字符串的情况  to_char('abc')
        if (size == 1) {
            Expression expression = expressions.get(0);
            if (expression instanceof LongValue) {
                LongValue longValue = (LongValue) expression;
                longValue.setStringValue(longValue.getStringValue() + Constants.AS_CHAR);
            }

            function.setName(Constants.CAST);
        }
        // to_char 函数 格式化日期 或 数值
        else {
            Expression expression = expressions.get(1);
            if (expression instanceof StringValue) {
                StringValue stringValue = (StringValue) expression;
                String value = stringValue.getValue();
                // 执行日期替换
                ExecutionDateReplacement(stringValue);
                if (Constants.FM_9999999990_00.equalsIgnoreCase(value)) {
                    // 将 to_char 函数 右边表达式的值 替换成 char
                    LongValue longValue = new LongValue(2);
                    // 替换 function 的表达式
                    expressions.set(1, longValue);
                    // 将 to_char 函数 转换成 convert
                    function.setName(Constants.FORMAT);
                    return;
                }

                function.setName(Constants.DATE_FORMAT);
            }
        }
    }

    /**
     * 处理 trunc 函数
     * trunc 函数可以截取数字和日期类型
     * 对应 mysql 中的 truncate 函数，但 truncate 函数不支持 日期截取，需要单独处理
     */
    private static void replaceTrunc(Function function) {
        ExpressionList parameters = function.getParameters();
        List<Expression> expressions = parameters.getExpressions();
        Expression firstExpression = expressions.get(0);
        if (firstExpression instanceof Column){
            Column column = (Column) firstExpression;
            if (Constants.ORACLE_SYSDATE.equalsIgnoreCase(column.getColumnName())){
                column.setColumnName(Constants.CURRENT_TIME);
            }
        }
        function.setName(Constants.TRUNCATE);
        if (expressions.size() == 1){
            return;
        }
        // 获取 trunc 函数的第二个参数
        Expression secondExpression = expressions.get(1);
        // 参数是 StringValue，说明是日期截取
        if (secondExpression instanceof StringValue) {
            StringValue stringValue = (StringValue) secondExpression;
            ExecutionTruncDateReplacement(stringValue);
            function.setName(Constants.DATE_FORMAT);
        }
        // 参数是 LongValue，说明是数值截取
        else if (secondExpression instanceof LongValue) {
            function.setName(Constants.TRUNCATE);
        }
    }


    /**
     * 处理 NVL 函数
     */
    private static void replaceNVL(Function function) {
        function.setName(Constants.IFNULL);
    }

    /**
     * 处理 DECODE 函数
     */
    private static void replaceDecode(Function function) {
        function.setName(Constants.IF);
        ExpressionList parameters = function.getParameters();
        List<Expression> expressions = parameters.getExpressions();
        Expression exp = expressions.get(0);
        Expression exp1 = expressions.get(1);
        if (exp1 instanceof NullValue){
            IsNullExpression isNullExpression = new IsNullExpression();
            isNullExpression.setLeftExpression(exp);
            expressions.remove(1);
            expressions.remove(0);
            expressions.add(0,isNullExpression);
        } else {
            EqualsTo equalsTo = new EqualsTo();
            equalsTo.setLeftExpression(exp);
            equalsTo.setRightExpression(exp1);
            expressions.remove(1);
            expressions.remove(0);
            expressions.add(0,equalsTo);
        }
    }

    /**
     * 执行日期替换
     */
    private static void ExecutionDateReplacement(StringValue stringValue) {
        String value = stringValue.getValue();
        if (Constants.YYYY.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y);
        } else if (Constants.YYYY_MM.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y_M);
        } else if (Constants.YYYY_MM_DD.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y_M_D);
        } else if (Constants.HH_24_MI_SS.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.H_I_S);
        } else if (Constants.MI_SS.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.I_S);
        } else if (Constants.SS.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.S);
        } else if (Constants.MI.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.I);
        } else if (Constants.MM.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.M);
        } else if (Constants.DD.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.D);
        } else if (Constants.HH_24.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.H);
        } else if (Constants.YYYY_MM_DD_HH_24.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y_M_D_H);
        } else if (Constants.YYYY_MM_DD_HH_24_MI.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y_M_D_H_I);
        } else if (Constants.YYYY_MM_DD_HH_24_MI_SS.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y_M_D_H_I_S);
        } else if (Constants.YYYY_Q.equalsIgnoreCase(value)) {
            // TODO 季节转换待解决
        } else if (Constants.YYYY_MM_DD1.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y_M_D1);
        }
    }

    private static void ExecutionTruncDateReplacement(StringValue stringValue) {
        String value = stringValue.getValue();
        if (Constants.YYYY.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y);
        } else if (Constants.MM.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y_M);
        } else if (Constants.DD.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y_M_D);
        } else if (Constants.HH_24.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y_M_D_H);
        } else if (Constants.MI.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y_M_D_H_I);
        } else if (Constants.SS.equalsIgnoreCase(value)) {
            stringValue.setValue(Constants.Y_M_D_H_I_S);
        }
    }

    public static void replaceColumn(Column column) {
        if (column == null){
            return;
        }
        String columnName = column.getColumnName();
        column.setColumnName(columnName.replace("\"", ""));
        if (Constants.ORACLE_SYSDATE.equalsIgnoreCase(columnName)){
            replaceSysdate(column);
        }
    }

    private static void replaceSysdate(Column column) {
        column.setColumnName(Constants.MYSQL_SYSDATE);
    }
}

